]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libipsec/esp_context.c
Update copyright headers after acquisition by secunet
[thirdparty/strongswan.git] / src / libipsec / esp_context.c
CommitLineData
64004973 1/*
24a8d125 2 * Copyright (C) 2012-2013 Tobias Brunner
64004973
TB
3 * Copyright (C) 2012 Giuliano Grassi
4 * Copyright (C) 2012 Ralf Sager
19ef2aec
TB
5 *
6 * Copyright (C) secunet Security Networks AG
64004973
TB
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 * for more details.
17 */
18
19#include <limits.h>
55e05aa2 20#include <stdint.h>
64004973
TB
21
22#include "esp_context.h"
23
24#include <library.h>
f05b4272 25#include <utils/debug.h>
64004973
TB
26
27/**
28 * Should be a multiple of 8
29 */
30#define ESP_DEFAULT_WINDOW_SIZE 128
31
32typedef struct private_esp_context_t private_esp_context_t;
33
34/**
35 * Private additions to esp_context_t.
36 */
37struct private_esp_context_t {
38
39 /**
40 * Public members
41 */
42 esp_context_t public;
43
44 /**
24a8d125 45 * AEAD wrapper or method to encrypt/decrypt/authenticate ESP packets
64004973 46 */
24a8d125 47 aead_t *aead;
64004973
TB
48
49 /**
50 * The highest sequence number that was successfully verified
51 * and authenticated, or assigned in an outbound context
52 */
b12c53ce 53 uint32_t last_seqno;
64004973
TB
54
55 /**
56 * The bit in the window of the highest authenticated sequence number
57 */
58 u_int seqno_index;
59
60 /**
61 * The size of the anti-replay window (in bits)
62 */
63 u_int window_size;
64
65 /**
66 * The anti-replay window buffer
67 */
68 chunk_t window;
69
70 /**
71 * TRUE in case of an inbound ESP context
72 */
73 bool inbound;
74};
75
76/**
77 * Set or unset a bit in the window.
78 */
79static inline void set_window_bit(private_esp_context_t *this,
80 u_int index, bool set)
81{
82 u_int i = index / CHAR_BIT;
83
84 if (set)
85 {
86 this->window.ptr[i] |= 1 << (index % CHAR_BIT);
87 }
88 else
89 {
90 this->window.ptr[i] &= ~(1 << (index % CHAR_BIT));
91 }
92}
93
94/**
95 * Get a bit from the window.
96 */
97static inline bool get_window_bit(private_esp_context_t *this, u_int index)
98{
99 u_int i = index / CHAR_BIT;
100
101 return this->window.ptr[i] & (1 << index % CHAR_BIT);
102}
103
104/**
105 * Returns TRUE if the supplied seqno is not already marked in the window
106 */
b12c53ce 107static bool check_window(private_esp_context_t *this, uint32_t seqno)
64004973
TB
108{
109 u_int offset;
110
111 offset = this->last_seqno - seqno;
112 offset = (this->seqno_index - offset) % this->window_size;
113 return !get_window_bit(this, offset);
114}
115
116METHOD(esp_context_t, verify_seqno, bool,
b12c53ce 117 private_esp_context_t *this, uint32_t seqno)
64004973
TB
118{
119 if (!this->inbound)
120 {
121 return FALSE;
122 }
123
124 if (seqno > this->last_seqno)
125 { /* |----------------------------------------|
126 * <---------^ ^ or <---------^ ^
127 * WIN H S WIN H S
128 */
129 return TRUE;
130 }
131 else if (seqno > 0 && this->window_size > this->last_seqno - seqno)
132 { /* |----------------------------------------|
133 * <---------^ or <---------^
134 * WIN ^ H WIN ^ H
135 * S S
136 */
137 return check_window(this, seqno);
138 }
139 else
140 { /* |----------------------------------------|
141 * ^ <---------^
142 * S WIN H
143 */
144 return FALSE;
145 }
146}
147
148METHOD(esp_context_t, set_authenticated_seqno, void,
b12c53ce 149 private_esp_context_t *this, uint32_t seqno)
64004973
TB
150{
151 u_int i, shift;
152
153 if (!this->inbound)
154 {
155 return;
156 }
157
158 if (seqno > this->last_seqno)
159 { /* shift the window to the new highest authenticated seqno */
160 shift = seqno - this->last_seqno;
161 shift = shift < this->window_size ? shift : this->window_size;
162 for (i = 0; i < shift; ++i)
163 {
164 this->seqno_index = (this->seqno_index + 1) % this->window_size;
165 set_window_bit(this, this->seqno_index, FALSE);
166 }
167 set_window_bit(this, this->seqno_index, TRUE);
168 this->last_seqno = seqno;
169 }
170 else
171 { /* seqno is inside the window, set the corresponding window bit */
172 i = this->last_seqno - seqno;
173 set_window_bit(this, (this->seqno_index - i) % this->window_size, TRUE);
174 }
175}
176
b12c53ce 177METHOD(esp_context_t, get_seqno, uint32_t,
64004973
TB
178 private_esp_context_t *this)
179{
180 return this->last_seqno;
181}
182
183METHOD(esp_context_t, next_seqno, bool,
b12c53ce 184 private_esp_context_t *this, uint32_t *seqno)
64004973
TB
185{
186 if (this->inbound || this->last_seqno == UINT32_MAX)
187 { /* inbound or segno would cycle */
188 return FALSE;
189 }
190 *seqno = ++this->last_seqno;
191 return TRUE;
192}
193
24a8d125
TB
194METHOD(esp_context_t, get_aead, aead_t*,
195 private_esp_context_t *this)
64004973 196{
24a8d125 197 return this->aead;
64004973
TB
198}
199
200METHOD(esp_context_t, destroy, void,
24a8d125 201 private_esp_context_t *this)
64004973
TB
202{
203 chunk_free(&this->window);
24a8d125 204 DESTROY_IF(this->aead);
64004973
TB
205 free(this);
206}
207
051fc25d
TB
208/**
209 * Create an AEAD algorithm
210 */
211static bool create_aead(private_esp_context_t *this, int alg,
212 chunk_t key)
213{
896d729a
TB
214 size_t salt = 0;
215
051fc25d
TB
216 switch (alg)
217 {
218 case ENCR_AES_GCM_ICV8:
219 case ENCR_AES_GCM_ICV12:
220 case ENCR_AES_GCM_ICV16:
19e0a71c 221 case ENCR_CHACHA20_POLY1305:
896d729a
TB
222 salt = 4;
223 break;
224 case ENCR_AES_CCM_ICV8:
225 case ENCR_AES_CCM_ICV12:
226 case ENCR_AES_CCM_ICV16:
227 case ENCR_CAMELLIA_CCM_ICV8:
228 case ENCR_CAMELLIA_CCM_ICV12:
229 case ENCR_CAMELLIA_CCM_ICV16:
230 salt = 3;
051fc25d
TB
231 break;
232 default:
233 break;
234 }
896d729a
TB
235 if (salt)
236 {
237 this->aead = lib->crypto->create_aead(lib->crypto, alg,
238 key.len - salt, salt);
239 }
051fc25d
TB
240 if (!this->aead)
241 {
242 DBG1(DBG_ESP, "failed to create ESP context: unsupported AEAD "
3f29ff82 243 "algorithm %N", encryption_algorithm_names, alg);
051fc25d
TB
244 return FALSE;
245 }
246 if (!this->aead->set_key(this->aead, key))
247 {
248 DBG1(DBG_ESP, "failed to create ESP context: setting AEAD key failed");
249 return FALSE;
250 }
251 return TRUE;
252}
253
64004973 254/**
24a8d125 255 * Create AEAD wrapper around traditional encryption/integrity algorithms
64004973 256 */
24a8d125
TB
257static bool create_traditional(private_esp_context_t *this, int enc_alg,
258 chunk_t enc_key, int int_alg, chunk_t int_key)
64004973 259{
a4b996c0
TB
260 crypter_t *crypter = NULL;
261 signer_t *signer = NULL;
3c81cb6f 262 iv_gen_t *ivg;
64004973 263
0e801276
TB
264 switch (enc_alg)
265 {
266 case ENCR_AES_CTR:
1f3a9fdd 267 case ENCR_CAMELLIA_CTR:
0e801276
TB
268 /* the key includes a 4 byte salt */
269 crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
270 enc_key.len - 4);
271 break;
272 default:
273 crypter = lib->crypto->create_crypter(lib->crypto, enc_alg,
274 enc_key.len);
275 break;
276 }
24a8d125 277 if (!crypter)
64004973
TB
278 {
279 DBG1(DBG_ESP, "failed to create ESP context: unsupported encryption "
3f29ff82 280 "algorithm %N", encryption_algorithm_names, enc_alg);
24a8d125 281 goto failed;
64004973 282 }
24a8d125 283 if (!crypter->set_key(crypter, enc_key))
64004973
TB
284 {
285 DBG1(DBG_ESP, "failed to create ESP context: setting encryption key "
286 "failed");
24a8d125 287 goto failed;
64004973
TB
288 }
289
3f29ff82 290 signer = lib->crypto->create_signer(lib->crypto, int_alg);
24a8d125 291 if (!signer)
64004973
TB
292 {
293 DBG1(DBG_ESP, "failed to create ESP context: unsupported integrity "
3f29ff82 294 "algorithm %N", integrity_algorithm_names, int_alg);
24a8d125 295 goto failed;
64004973 296 }
24a8d125 297 if (!signer->set_key(signer, int_key))
64004973
TB
298 {
299 DBG1(DBG_ESP, "failed to create ESP context: setting signature key "
300 "failed");
24a8d125
TB
301 goto failed;
302 }
3c81cb6f
MW
303 ivg = iv_gen_create_for_alg(enc_alg);
304 if (!ivg)
305 {
306 DBG1(DBG_ESP, "failed to create ESP context: creating iv gen failed");
307 goto failed;
308 }
309 this->aead = aead_create(crypter, signer, ivg);
24a8d125
TB
310 return TRUE;
311
312failed:
313 DESTROY_IF(crypter);
314 DESTROY_IF(signer);
315 return FALSE;
316}
317
318/**
319 * Described in header.
320 */
321esp_context_t *esp_context_create(int enc_alg, chunk_t enc_key,
322 int int_alg, chunk_t int_key, bool inbound)
323{
324 private_esp_context_t *this;
325
326 INIT(this,
327 .public = {
328 .get_aead = _get_aead,
329 .get_seqno = _get_seqno,
330 .next_seqno = _next_seqno,
331 .verify_seqno = _verify_seqno,
332 .set_authenticated_seqno = _set_authenticated_seqno,
333 .destroy = _destroy,
334 },
335 .inbound = inbound,
336 .window_size = ESP_DEFAULT_WINDOW_SIZE,
337 );
338
051fc25d
TB
339 if (encryption_algorithm_is_aead(enc_alg))
340 {
341 if (!create_aead(this, enc_alg, enc_key))
342 {
343 destroy(this);
344 return NULL;
345 }
346 }
347 else
24a8d125 348 {
051fc25d
TB
349 if (!create_traditional(this, enc_alg, enc_key, int_alg, int_key))
350 {
351 destroy(this);
352 return NULL;
353 }
64004973
TB
354 }
355
356 if (inbound)
357 {
358 this->window = chunk_alloc(this->window_size / CHAR_BIT + 1);
359 memset(this->window.ptr, 0, this->window.len);
360 }
361 return &this->public;
362}